﻿using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace LogikBug.Async.Tasks
{
	/// <summary>
	/// 
	/// </summary>
	[Guid("5cbecb0f-7798-498a-9c37-d10109a5a2c2")]
	public class TimedAgentController : AgentController
	{
		#region Events

		#region Static Events

		/// <summary>
		/// The static event that is invoked when the any
		/// <see cref="TimedAgentController"/>'s timer has elapsed.
		/// </summary>
		public static event Action<TimedAgentController, DateTime> OnTimerElapsedGlobal;

		#endregion

		#region Instance Events

		/// <summary>
		/// The event that is invoked when the current
		/// <see cref="TimedAgentController"/>'s timer has elapsed.
		/// </summary>
		public event Action<DateTime> OnTimerElapsed;

		#endregion

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="TimedAgentController"/>
		/// using the default <see cref="AgentSettings"/>.
		/// </summary>
		public TimedAgentController() : this(new AgentSettings())
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TimedAgentController"/>
		/// using the specified <paramref name="controllerEventHandler"/>.
		/// </summary>
		/// <param name="controllerEventHandler">The object that handles the events of this <see cref="AgentController"/>.</param>
		public TimedAgentController(IAgentControllerEventHandler controllerEventHandler) : this(new AgentSettings(), controllerEventHandler)
		{
		}

		/// <summary>
		/// Initializes a new instance of the
		/// <see cref="TimedAgentController"/> using the specified <paramref name="settings"/>.
		/// </summary>
		/// <param name="settings">The <see cref="AgentSettings"/>
		/// used in the initialization of the current instance.</param>
		public TimedAgentController(AgentSettings settings) : this(settings, null)
		{
		}

		/// <summary>
		/// Initializes a new instance of the
		/// <see cref="TimedAgentController"/> using the specified <paramref name="settings"/>.
		/// </summary>
		/// <param name="settings">The <see cref="AgentSettings"/>
		/// used in the initialization of the current instance.</param>
		/// <param name="controllerEventHandler">The object that handles the events of this <see cref="AgentController"/>.</param>
		public TimedAgentController(AgentSettings settings, IAgentControllerEventHandler controllerEventHandler) : base(settings, controllerEventHandler)
		{
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the <see cref="Timer"/> used with the current instance.
		/// </summary>
		protected Timer UpdateTimer { get; set; }

		/// <summary>
		/// Gets the last <see cref="DateTime"/> the <see cref="Timer"/> executed.
		/// </summary>
		public DateTime LastUpdate { get; protected set; }

		#endregion

		#region Methods

		private void UpdateTimerInterval(object state)
		{
			LastUpdate = DateTime.Now;

			UpdateTimerIntervalCore(state);

			if (OnTimerElapsed != null)
			{
				OnTimerElapsed(LastUpdate);
			}

			if (OnTimerElapsedGlobal != null)
			{
				OnTimerElapsedGlobal(this, LastUpdate);
			}
		}

		/// <summary>
		/// When overridden in a derived class, provides logic that
		/// should be executed on every interval of the <see cref="Timer"/>.
		/// </summary>
		/// <param name="state"></param>
		protected virtual void UpdateTimerIntervalCore(object state)
		{
		}

		/// <summary>
		/// Initializes the <see cref="Timer"/> using the <paramref name="refreshIntervalInMinutes"/>.
		/// </summary>
		/// <param name="refreshIntervalInMinutes">
		/// A double value that is parsed by the <see cref="TimeSpan.FromMinutes"/> method.
		/// <remarks>
		///	If the value is less than or eaual to 0.0d, then timer will
		///	be will be initialized with the refresh interval of 1 minute (1.0d).
		/// </remarks>
		/// </param>
		protected virtual void InitUpdateTimer(double refreshIntervalInMinutes)
		{
			if (refreshIntervalInMinutes <= 0.0d)
			{
				refreshIntervalInMinutes = 1.0d;
			}

			LastUpdate = DateTime.Now;
			UpdateTimer = new Timer(UpdateTimerInterval, this, TimeSpan.Zero, TimeSpan.FromMinutes(refreshIntervalInMinutes));
		}

		/// <summary>
		/// Disposes the resources associated with this current instance.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);

			if (disposing)
			{
				if (UpdateTimer != null)
				{
					UpdateTimer.Dispose();
					UpdateTimer = null;
				}

				LastUpdate = DateTime.MinValue;
			}
		}

		public override void Initialize()
		{
			InitUpdateTimer(Settings.TimerInterval);
			base.Initialize();
		}

		#endregion
	}
}
